package com.bestcem.xm.txtanls.grpc.service;

import cn.hutool.core.lang.Validator;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.txtanls.grpc.convert.ChartConvert;
import com.bestcem.xm.txtanls.grpc.service.param.chart.*;
import com.bestcem.xm.txtanls.grpc.v1.services.*;
import com.bestcem.xm.txtanls.service.ChartService;
import com.bestcem.xm.txtanls.service.dto.chart.*;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 文本分析展示GRpc服务端接口
 *
 * @author jy.zhao
 * @version 1.0
 * @date 2021/5/13 13:39
 **/
@Slf4j
@GrpcService
public class ChartGrpcService extends ChartServiceGrpc.ChartServiceImplBase {

    @Autowired
    private ChartService chartService;

    /**
     * 观点统计 grpc服务端接口
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/13 13:42
     **/
    @Override
    public void getViewpointStat(GetViewpointStatRequest request, StreamObserver<GetViewpointStatResponse> responseObserver) {
        GetViewpointStatResponse.Builder builder = GetViewpointStatResponse.newBuilder();
        // 参数转换为BaseChartParam
        BaseChartParam baseChartParam = ChartConvert.requestToBaseChartParam(request.getBaseChart());
        // 使用注解校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(baseChartParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(baseChartParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 调用服务
        ServiceResult<ViewpointStatResultDTO> serviceResult = chartService.statViewpoint(baseChartParam);
        // 转换结果
        if (serviceResult.isSuccess()) {
            List<ViewpointGroupStat> viewpointGroupStat = ChartConvert.viewpointStatToGrpcResult(serviceResult.getData().getViewPointGroupStatDTOS());
            builder.addAllResults(viewpointGroupStat);
            builder.setTotal(serviceResult.getData().getTotal());
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 观点评价变化 grpc服务端接口
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/13 13:40
     **/
    @Override
    public void getViewpointEvaluate(GetViewpointEvaluateRequest request, StreamObserver<GetViewpointEvaluateResponse> responseObserver) {
        GetViewpointEvaluateResponse.Builder builder = GetViewpointEvaluateResponse.newBuilder();
        // 参数转换为BaseChartParam
        ViewpointEvaluateParam viewEvaluateParam = ChartConvert.requestToViewEvaluateParam(request);
        // 使用注解校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(viewEvaluateParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(viewEvaluateParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        if (validId(viewEvaluateParam.getViewpointGid())) {
            builder.setStatus(RpcStatusResult.error("观点id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 调用服务
        ServiceResult<ViewPointEvaluateDTO> serviceResult = chartService.statViewpointEvaluate(viewEvaluateParam);
        // 返回结果
        if (serviceResult.isSuccess()) {
            ViewpointEvaluate viewpointEvaluate = ChartConvert.viewpointEvaluateToGrpcResult(serviceResult.getData());
            builder.setResult(viewpointEvaluate);
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 总体情感细分 grpc服务端接口
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/14 11:46
     **/
    @Override
    public void getEmotionDetail(GetEmotionDetailRequest request, StreamObserver<GetEmotionDetailResponse> responseObserver) {
        GetEmotionDetailResponse.Builder builder = GetEmotionDetailResponse.newBuilder();
        // 参数转换为BaseChartParam
        BaseChartParam baseChartParam = ChartConvert.requestToBaseChartParam(request.getBaseChart());
        // 使用注解校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(baseChartParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(baseChartParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 调用服务
        ServiceResult<EmotionDetailDTO> serviceResult = chartService.statEmotion(baseChartParam);
        // 转换为grpc数据，返回结果
        if (serviceResult.isSuccess()) {
            builder.setResult(ChartConvert.emotionDetailDTOToGrpcResult(serviceResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 总体情感趋势 grpc服务端接口
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/14 13:58
     **/
    @Override
    public void getEmotionTrend(GetEmotionTrendRequest request, StreamObserver<GetEmotionTrendResponse> responseObserver) {
        GetEmotionTrendResponse.Builder builder = GetEmotionTrendResponse.newBuilder();
        // 参数转换为BaseChartParam
        BaseChartParam baseChartParam = ChartConvert.requestToBaseChartParam(request.getBaseChart());
        // 使用注解校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(baseChartParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(baseChartParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<EmotionDTO>> serviceResult = chartService.statEmotionTrend(baseChartParam);
        // 转换为grpc数据，返回结果
        if (serviceResult.isSuccess()) {
            List<EmotionDTO> resultData = serviceResult.getData();
            builder.addAllResults(ChartConvert.emotionDTOToGrpcResult(resultData));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 词云图 grpc服务端接口
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/14 14:07
     **/
    @Override
    public void getWordCloud(GetWordCloudRequest request, StreamObserver<GetWordCloudResponse> responseObserver) {
        GetWordCloudResponse.Builder builder = GetWordCloudResponse.newBuilder();
        // 转换参数为WorkCloudParam
        WorkCloudParam workCloudParam = ChartConvert.requestToWorkCloudParam(request);
        // 使用注解校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(workCloudParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(workCloudParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验topicid格式
        if (validId(workCloudParam.getTopicId())) {
            builder.setStatus(RpcStatusResult.error("话题id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<WorkCloudDataDTO>> serviceResult = chartService.statKeyword(workCloudParam);
        // 转换为grpc数据，返回结果
        if (serviceResult.isSuccess()) {
            builder.addAllResults(ChartConvert.workCloudDataDTOToGrpcResult(serviceResult.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 话题引用
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/17 16:11
     **/
    @Override
    public void getTopicReferenceRate(GetTopicReferenceRateRequest request, StreamObserver<GetTopicReferenceRateResponse> responseObserver) {
        GetTopicReferenceRateResponse.Builder builder = GetTopicReferenceRateResponse.newBuilder();
        // 转换请求参数为TopicReferenceParam
        TopicReferenceParam topicReferenceRateParam = ChartConvert.requestToTopicReferenceRateParam(request);
        // 校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(topicReferenceRateParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(topicReferenceRateParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验topicid格式
        if (validId(topicReferenceRateParam.getTopicGid())) {
            builder.setStatus(RpcStatusResult.error("话题id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<TopicReferenceRateDTO> serviceResult = chartService.statTopicReference(topicReferenceRateParam);
        // 转换结果
        if (serviceResult.isSuccess()) {
            TopicReferenceRate topicReferenceRate = ChartConvert.topicReferenceRateDTOToGrpcResult(serviceResult.getData());
            builder.setResult(topicReferenceRate);
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 话题关联统计
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/17 16:11
     **/
    @Override
    public void getTopicRelation(GetTopicRelationRequest request, StreamObserver<GetTopicRelationResponse> responseObserver) {
        GetTopicRelationResponse.Builder builder = GetTopicRelationResponse.newBuilder();
        // 转换请求参数为TopicRelationParam
        TopicRelationParam topicRelationParam = ChartConvert.requestToTopicRelationParam(request);
        // 校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(topicRelationParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(topicRelationParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验topicid格式
        if (validId(topicRelationParam.getTopicId())) {
            builder.setStatus(RpcStatusResult.error("话题id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<TopicRelationDTO>> serviceResult = chartService.statTopicRelation(topicRelationParam);
        // 对返回结果进行转换
        if (serviceResult.isSuccess()) {
            List<TopicRelation> topicRelationList = ChartConvert.topicRelationDTOToGrpcResult(serviceResult.getData());
            builder.addAllResults(topicRelationList);
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 话题关联统计
     *
     * @param request          请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/5/17 16:11
     **/
    @Override
    public void getTopicReferenceTrend(GetTopicReferenceTrendRequest request, StreamObserver<GetTopicReferenceTrendResponse> responseObserver) {
        GetTopicReferenceTrendResponse.Builder builder = GetTopicReferenceTrendResponse.newBuilder();
        // 转换请求参数为topicsReferenceTrendParam
        TopicReferenceTrendParam topicsReferenceTrendParam = ChartConvert.requestToTopicReferenceTrendParam(request);
        // 校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(topicsReferenceTrendParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(topicsReferenceTrendParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 如果话题id和话题组id都为空，返回错误
        if (Validator.isEmpty(topicsReferenceTrendParam.getTopicId()) && Validator.isEmpty(topicsReferenceTrendParam.getTopicGid())) {
            builder.setStatus(RpcStatusResult.error("话题id和话题组id不能都为空"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验topicid格式
        if (validId(topicsReferenceTrendParam.getTopicId())) {
            builder.setStatus(RpcStatusResult.error("话题id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验topicGid格式
        if (validId(topicsReferenceTrendParam.getTopicGid())) {
            builder.setStatus(RpcStatusResult.error("话题组id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<TopicStatDTO>> serviceResult = chartService.statTopicReferenceTrend(topicsReferenceTrendParam);
        // 对返回结果进行转换
        if (serviceResult.isSuccess()) {
            List<TopicStat> topicStatList = ChartConvert.topicReferenceTrendDTOToGrpcResult(serviceResult.getData());
            builder.addAllResults(topicStatList);
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 观点情感分布变化趋势
     * @param request 请求
     * @param responseObserver 响应
     * @author jy.zhao
     * @date 2021/8/5 11:32
     **/
    @Override
    public void getViewpointEvaluateTrend(GetViewpointEvaluateTrendRequest request, StreamObserver<GetViewpointEvaluateTrendResponse> responseObserver) {
        GetViewpointEvaluateTrendResponse.Builder builder = GetViewpointEvaluateTrendResponse.newBuilder();
        // 转换请求参数为viewpointEvaluateTrendParam
        ViewpointEvaluateTrendParam viewpointEvaluateTrendParam = ChartConvert.requestToViewpointEvaluateTrendParam(request);
        // 校验参数
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(viewpointEvaluateTrendParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验BaseChartParam的时间参数，field字段
        String errmsg = validBaseChartParam(viewpointEvaluateTrendParam);
        if (Validator.isNotEmpty(errmsg)) {
            builder.setStatus(RpcStatusResult.error(errmsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 如果观点id和观点组id都为空，返回错误
        if (Validator.isEmpty(viewpointEvaluateTrendParam.getViewId()) && Validator.isEmpty(viewpointEvaluateTrendParam.getViewGid())) {
            builder.setStatus(RpcStatusResult.error("观点id和观点组id不能都为空"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验ViewId格式
        if (validId(viewpointEvaluateTrendParam.getViewId())) {
            builder.setStatus(RpcStatusResult.error("观点id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        // 校验ViewGid格式
        if (validId(viewpointEvaluateTrendParam.getViewGid())) {
            builder.setStatus(RpcStatusResult.error("观点组id格式错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<ViewpointEvaluateStatDTO>> serviceResult = chartService.statViewpointEvaluateTrend(viewpointEvaluateTrendParam);
        // 对返回结果进行转换
        if (serviceResult.isSuccess()) {
            List<ViewpointEvaluateStat> viewpointEvaluateStats = ChartConvert.viewpointEvaluateStatDTOToGrpcResult(serviceResult.getData());
            builder.addAllResults(viewpointEvaluateStats);
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 校验baseChartParam额外参数
     *
     * @param baseChartParam 参数
     * @return String
     * @author jy.zhao
     * @date 2021/5/26 15:05
     **/
    public String validBaseChartParam(BaseChartParam baseChartParam) {
        if (validId(baseChartParam.getFieldId())) {
            return "fieldId格式错误";
        }
        PeriodTimeDTO periodTime = baseChartParam.getTimeRangeDTO().getPeriodTime();
        if (periodTime.getStartTime().isAfter(periodTime.getEndTime())) {
            return "周期开始时间必须小于结束时间";
        }
        return null;
    }

    /**
     * 校验id格式是否有误
     *
     * @param id 传入的id
     * @return Boolean
     * @author jy.zhao
     * @date 2021/5/26 15:06
     **/
    public boolean validId(String id) {
        if (Validator.isNotEmpty(id) && !Pattern.matches(RegTypes.OBJECT_ID, id)) {
            return true;
        }
        return false;
    }

}
